#include "ctcpclient.h"

#include<QThread>
#include<QTcpSocket>

const qint64 kMaxBufLen = 33554432; // 32MB 缓存

CTcpClient::CTcpClient():
    m_pThread(new QThread()),
    m_pTcp(new QTcpSocket()),
    m_iLen(-1),
    m_isConn(false)
{
    m_readBuf.resize(kMaxBufLen);

    m_pTcp->moveToThread(m_pThread);
    this->moveToThread(m_pThread);
    m_pThread->start();

    connect(m_pTcp, &QTcpSocket::readyRead, this, &CTcpClient::slotDataReady,
            Qt::DirectConnection);

    connect(m_pTcp, SIGNAL(error(QAbstractSocket::SocketError)),
            this,   SLOT(slotDisconnected()));
    //=========================================================================
    connect(this, &CTcpClient::sigDisConn, this, &CTcpClient::slotDisConn);
    connect(this, &CTcpClient::sigConnetServ, this,
            &CTcpClient::slotConnetServ);
    connect(this, &CTcpClient::sigWrite, this, &CTcpClient::slotWrite);
   }

CTcpClient::~CTcpClient()
{
    DisConn();
    m_pThread->quit();
    m_pThread->wait();
   // delete m_pTcp;
  //  m_pTcp = 0;
    delete m_pThread;
    m_pThread = 0;
}

bool CTcpClient::IsConn() const
{
    return m_isConn;
}

bool CTcpClient::ConnetServ(QString strServIp, quint16 nSevPort)
{
    m_lockConnServ.lock();
    const int nAvail = m_semConnServ.available();
    if(nAvail > 0)
    {
        m_semConnServ.tryAcquire(nAvail);
    }
    emit sigConnetServ(strServIp, nSevPort);
    const bool bWait = m_semConnServ.tryAcquire(1, 5000);
    m_lockConnServ.unlock();
    return bWait ? m_isConn : false;
}
void CTcpClient::slotConnetServ(const QString strServIP,
                                const quint16 nServPort)
{
    m_pTcp->abort();
    m_isConn = false;
    if(strServIP.length() < 1)
    {
        m_semConnServ.release();
        return;
    }

    m_pTcp->connectToHost(strServIP, nServPort);
    if(false == m_pTcp->waitForConnected(500))
    {
        qDebug()<<"连接服务器失败！";
        m_semConnServ.release();
        return;
    }
    m_isConn = true;
    m_semConnServ.release();
}

void CTcpClient::slotDisconnected()
{
    DisConn();
}

void CTcpClient::DisConn()
{
    m_lockDisConn.lock();
    const int nAvail = m_semDisConn.available();
    if(nAvail > 0)
    {
        m_semDisConn.tryAcquire(nAvail);
    }
    emit sigDisConn();
    m_semDisConn.tryAcquire(1, 5000);
    m_lockDisConn.unlock();
}

void CTcpClient::slotDisConn()
{
	m_pTcp->disconnectFromHost();
#if 1
	/** 2021-01-13 15:47：QAbstractSocket::waitForDisconnected() is not allowed in UnconnectedState */
	if(m_pTcp->state() != QAbstractSocket::UnconnectedState)
		m_pTcp->waitForDisconnected(1000);
#else
	m_pTcp->waitForDisconnected(1000);
#endif
    m_pTcp->abort();
    m_isConn = false;
    m_semDisConn.release();
}

void CTcpClient::slotDataReady()
{
    QTcpSocket *const pTcp = m_pTcp;
    m_readBuf = pTcp->read(kMaxBufLen);
    emit sigDataReady(m_readBuf);
}

qint64 CTcpClient::Write(const char* data, qint64 maxSize)
{
    if(!m_isConn) return -1;
    m_lockWrite.lock();
    const int nAvail = m_semWrite.available();
    if(nAvail > 0)
    {
        m_semWrite.tryAcquire(nAvail);
    }
    emit sigWrite(data, maxSize);
    const bool bWait = m_semWrite.tryAcquire(1, 5000);
    m_lockWrite.unlock();
    QMutexLocker lk(&m_lockWriteLen);
    qint64 iRet = bWait ? m_iLen : 0;
    return iRet;
}

void CTcpClient::slotWrite(const char *pch, qint64 maxSize)
{
    m_lockWriteLen.lock();
    m_iLen = -1;
    if(m_pTcp->isOpen())
    {
        m_iLen = (maxSize < 0)? m_pTcp->write(pch):
                                m_pTcp->write(pch, maxSize);
        m_pTcp->waitForBytesWritten(300);
    }
    m_lockWriteLen.unlock();
    m_semWrite.release();
}
